package com.xneure.function;

import com.xneure.code.exception.FunctionException;
import com.xneure.function.enums.TokenType;
import com.xneure.function.mode.FunctionBase;
import com.xneure.function.node.FunctionList;
import com.xneure.function.node.FunctionNode;
import com.xneure.function.node.IFuncionList;
import com.xneure.function.node.RelationNode;
import com.xneure.function.node.Token;
import com.xneure.function.operator.Addition;
import com.xneure.function.operator.And;
import com.xneure.function.operator.Division;
import com.xneure.function.operator.Multiplication;
import com.xneure.function.operator.Or;
import com.xneure.function.operator.Priority;
import com.xneure.function.operator.Subtraction;

public class FunctionParse{
	private SyntaxAnalyze analyze = new SyntaxAnalyze();
	private Token[] token;
	private int tokenSize = 0;
	private int level = 0;

	public IFuncionList parse(String funStr){
		analyze.analyze(funStr);
		token = analyze.getToken();
		tokenSize = token.length;
		IFuncionList funList = new FunctionList();
		buildFunction(token,0,funList);
		return funList;
	}

	private int buildFunction(Token[] token,int point,IFuncionList funList){
		IFuncionList _funList = new FunctionList();
		funList.addFunctionNode(_funList);
		FunctionNode fNode = null;
		for(int i = point;i < tokenSize;i++){
			Token tk = token[i];
			Relation op = getRelation(tk);
			if(null != op){
				RelationNode operator = new RelationNode(op);
				operator.setToken(tk);
				if(op instanceof LogicRelation) {
					_funList = new FunctionList();
					_funList.setRelation(operator);
					funList.addFunctionNode(_funList);
				}else {
					fNode.setOperatorNode(operator);
				}
			}else if(tk.type == TokenType.RIGHT_BRACKETS){
				if(level-- < 0){
					throw new FunctionException(String.format("%1s:%2s 缺失 (",tk.line,tk.endPoint));
				}
				if(level < 1){
					return i;
				}
			}else if(tk.type == TokenType.FUNCTION || tk.type == TokenType.LEFT_BRACKETS){
				FunctionBase fun = FunctionCollect.getFunction(token[i].data);
				fNode = new FunctionNode(fun);
				fNode.setToken(tk);
				_funList.addFunctionNode(fNode);
				++level;
				if(fun instanceof Priority){
					IFuncionList fl = new FunctionList();
					i = buildFunction(token,i + 1,fl);
					if(i == tokenSize && level > 0){
						throw new FunctionException(String.format("%1s:%2s 缺失 )",tk.line,tk.endPoint));
					}
					fNode.addParam(fl);
				}else{
					i = buildParam(token,i + 2,fNode);
					fNode.verify();
				}
			}
		}
		return tokenSize;
	}

	private int buildParam(Token[] token,int point,FunctionNode funNode){
		int i = point;
		for(;i < tokenSize;i++){
			Token tk = token[i];
			if(tk.type == TokenType.RIGHT_BRACKETS){
				level--;
				return i;
			}else if(tk.type == TokenType.DOT){
			}else{
				if(i - 1 < tokenSize && token[i + 1].type == TokenType.LEFT_BRACKETS){
					level++;
					IFuncionList fl = new FunctionList();
					funNode.addParam(fl);
					i = buildFunction(token,i,fl);
				}else{
					funNode.addParam(tk.data);
				}
			}
		}
		throw new FunctionException(String.format("%1s:%2s 缺失 )",token[point].line,token[point].endPoint));
	}

	public Relation getRelation(Token tk){
		switch(tk.type){
			case ADD:
				return new Addition();
			case DIVISION:
				return new Division();
			case MULTIPLICATION:
				return new Multiplication();
			case SUBTRACTION:
				return new Subtraction();
			case AND:
				return new And();
			case OR:
				return new Or();
			default:
				return null;
		}
	}
}
